package org.goldfish.distributed_framework.server;

import org.goldfish.distributed_framework.api.Service;
import org.goldfish.distributed_framework.config.ServerConfig;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class RpcServer {

    public static void start(ServerConfig config) throws Exception { // 注意这里抛 Exception
        // 1. 注册服务到本地 ServiceProvider
        registerLocalService(config);

        // 2. 向注册中心注册
        registerToRegistry(config);

        // 3. 启动Socket服务
        ServerSocket serverSocket = new ServerSocket(config.getPort());
        System.out.println("RPC 服务端启动成功，端口: " + config.getPort());

        ExecutorService threadPool = new ThreadPoolExecutor(
                4, 10, 60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>())
                // 暂时改成阻塞式
        {
            @Override
            public Future<?> submit(Runnable task) {
                task.run();
                return null;
            }
        };

        while (true) {
            Socket client = serverSocket.accept();
            System.out.println("接受到新的客户端连接: " + client.getInetAddress());
//            threadPool.submit(new RpcWorker(client));
            new RpcWorker(client).run();
        }
    }

    private static void registerLocalService(ServerConfig config) throws Exception {
        Object serviceInstance = Class.forName(config.getServiceImpl())
                .getDeclaredConstructor()
                .newInstance();
        if (!(serviceInstance instanceof Service service)) {
            throw new IllegalArgumentException("服务实现类必须实现 Service 接口");
        }
        ServiceProvider.register(config.getServiceName(), service);
        System.out.println("本地服务注册成功: " + config.getServiceImpl());
    }

    private static void registerToRegistry(ServerConfig config) {
        String[] parts = config.getRegistryAddress().split(":");
        if (parts.length != 2) {
            throw new IllegalArgumentException("registryAddress 配置错误，应为 host:port");
        }

        String localAddress;
        try {
            localAddress = getLocalAddress() + ":" + config.getPort();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String urlStr = "http://" + parts[0] + ":" + parts[1] + "/register";
        String content = "service=" + config.getServiceName() + "&address=" + localAddress;
        System.out.println("注册中心地址: " + urlStr);
        System.out.println("注册信息: " + content);
        try {
            String response = sendPostRequest(urlStr, content);
            System.out.println("注册成功: " + config.getServiceName() + " -> " + response);
        } catch (IOException e) {
            System.err.println("注册到注册中心失败");
            e.printStackTrace();
        }
    }

    private static String sendPostRequest(String urlStr, String content) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL(urlStr).openConnection();
        connection.setRequestMethod("POST");
        connection.setConnectTimeout(20000);
        connection.setReadTimeout(20000);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setDoOutput(true);

        try (OutputStream out = connection.getOutputStream()) {
            out.write(content.getBytes(StandardCharsets.UTF_8));
        }

        try (
                InputStream in = connection.getInputStream();
                InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader bufferedReader = new BufferedReader(reader);
        ) {
            return bufferedReader.lines().collect(Collectors.joining());
        }
    }

    private static String getLocalAddress() throws SocketException {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface ni = interfaces.nextElement();
            if (ni.isVirtual() || !ni.isUp() || ni.isLoopback()) continue;

            Enumeration<InetAddress> addresses = ni.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress addr = addresses.nextElement();
                if (addr instanceof Inet4Address && addr.isSiteLocalAddress()) {
                    return addr.getHostAddress();
                }
            }
        }
        return "127.0.0.1";
    }

}
